{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## _*Using PySCF driver*_\n",
    "\n",
    "Qiskit Chemistry supports a number of different chemistry drivers, i.e chemistry programs and software libraries, which are used to compute integrals that are then used to build the second quantized Hamiltonian in the FermionicOperator.\n",
    "\n",
    "Drivers include Gaussian 16, PyQuante, PySCF, PSI4 and HDF5. The main Qiskit documentation has more information on [drivers](https://qiskit.org/documentation/aqua/chemistry/qiskit_chemistry_drivers.html).\n",
    "\n",
    "For non-Windows platforms (where PySCF has no pre-built packages), the PySCF driver is installed as a  dependent when you `pip install qiskit-aqua`. HDF5 support is built into Qiskit Aqua. If you would like/prefer to use one of the other drivers then refer to the above link for installation and usage guidance.\n",
    "\n",
    "Note: drivers were written to allow existing users of them to leverage creating the molecular input in a native way for the driver. While Multiplicity (2S+1) is commonly used to specify the overall spin of the molecule, PySCF uses Spin (2S) if you are programming directly with its API and that is what is exposed here. For a singlet system, as in the example below i.e. equal numbers of alpha and beta electrons, the overall spin here is 0 and 2S is 0 (Multiplicity would have been 1).\n",
    "\n",
    "This notebook has been written to use the PySCF chemistry driver."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from qiskit import BasicAer\n",
    "\n",
    "from qiskit.aqua import QuantumInstance\n",
    "from qiskit.aqua.algorithms import VQE, NumPyMinimumEigensolver\n",
    "from qiskit.aqua.components.optimizers import L_BFGS_B\n",
    "from qiskit.circuit.library import TwoLocal\n",
    "\n",
    "from qiskit.chemistry import FermionicOperator\n",
    "from qiskit.chemistry.drivers import PySCFDriver, UnitsType"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# using driver to get fermionic Hamiltonian\n",
    "# PySCF example\n",
    "driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', unit=UnitsType.ANGSTROM,\n",
    "                     charge=0, spin=0, basis='sto3g')\n",
    "molecule = driver.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<qiskit.aqua.operators.legacy.weighted_pauli_operator.WeightedPauliOperator at 0x1343fd310>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# get fermionic operator and mapping to qubit operator\n",
    "ferOp = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals)\n",
    "qubitOp = ferOp.mapping(map_type='JORDAN_WIGNER', threshold=0.00000001)\n",
    "qubitOp.chop(10**-10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The exact ground state energy is: -1.8572750302023824\n"
     ]
    }
   ],
   "source": [
    "# Using exact eigensolver to get the smallest eigenvalue\n",
    "exact_eigensolver = NumPyMinimumEigensolver(qubitOp)\n",
    "ret = exact_eigensolver.run()\n",
    "print('The exact ground state energy is: {}'.format(ret.eigenvalue.real))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Minimum value: -1.85727503015946\n",
      "Parameters: [ 1.38109648  3.0799131   0.87875453  1.95614111  2.64747338  2.33717554\n",
      " -3.47335053  6.71224521  3.55015004 -4.56000624  2.14531307  1.53903717\n",
      "  1.55226763 -2.61425629 -4.63381128  4.30440231  2.49559166  6.65245959\n",
      "  4.42675124 -3.74108666  4.93775431  5.66278263  2.00123821 -3.9869573 ]\n"
     ]
    }
   ],
   "source": [
    "# setup VQE \n",
    "# setup optimizer, use L_BFGS_B optimizer for example\n",
    "lbfgs = L_BFGS_B(maxfun=1000, factr=10, iprint=10)\n",
    "\n",
    "# setup variational form generator (generate trial circuits for VQE)\n",
    "var_form = TwoLocal(qubitOp.num_qubits, 'ry', 'cz', reps=5, entanglement='linear')\n",
    "\n",
    "# setup VQE with operator, variational form, and optimizer\n",
    "vqe_algorithm = VQE(qubitOp, var_form, lbfgs)\n",
    "\n",
    "backend = BasicAer.get_backend('statevector_simulator')\n",
    "quantum_instance = QuantumInstance(backend)\n",
    "\n",
    "results = vqe_algorithm.run(quantum_instance)\n",
    "print(\"Minimum value: {}\".format(results.eigenvalue.real))\n",
    "print(\"Parameters: {}\".format(results.optimal_point))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
